﻿using FS_Unitys.Basic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace FS_Unitys.Unitys
{
    public sealed class WebUtils
    {
        private int _timeout = 100000;

        private string m_Username;
        private string m_Password;

        public WebUtils()
        {

        }

        public WebUtils(string username, string password)
        {
            m_Username = username;
            m_Password = password;
        }

        /// <summary>
        /// 请求与响应的超时时间
        /// </summary>
        public int Timeout
        {
            get { return this._timeout; }
            set { this._timeout = value; }
        }

        public string HttpPostWebService(string url, string method, IDictionary<string, object> dicParam)
        {
            string param = ToolHelper.BuildQuery(dicParam);
            string result = string.Empty;
            //string param = string.Empty;
            byte[] bytes = null;

            Stream writer = null;
            HttpWebRequest request = null;
            HttpWebResponse response = null;

            // param = HttpUtility.UrlEncode("param1") + "=" + HttpUtility.UrlEncode(num1) + "&" + HttpUtility.UrlEncode("param2") + "=" + HttpUtility.UrlEncode(num2);
            bytes = Encoding.UTF8.GetBytes(param);

            request = (HttpWebRequest)WebRequest.Create(url + "/" + method);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = bytes.Length;

            try
            {
                writer = request.GetRequestStream();        //获取用于写入请求数据的Stream对象
            }
            catch (Exception ex)
            {
                return "";
            }

            writer.Write(bytes, 0, bytes.Length);       //把参数数据写入请求数据流
            writer.Close();

            try
            {
                response = (HttpWebResponse)request.GetResponse();      //获得响应
            }
            catch (WebException ex)
            {
                return "";
            }

            #region 这种方式读取到的是一个返回的结果字符串
            Stream stream = response.GetResponseStream();        //获取响应流
            XmlTextReader Reader = new XmlTextReader(stream);
            Reader.MoveToContent();
            result = Reader.ReadInnerXml();
            #endregion

            #region 这种方式读取到的是一个Xml格式的字符串
            //StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            //result = reader.ReadToEnd();
            #endregion 

            response.Dispose();
            response.Close();

            //reader.Close();
            //reader.Dispose();

            Reader.Dispose();
            Reader.Close();

            stream.Dispose();
            stream.Close();

            return result;
        }

        public string HttpPostWebServiceForJson(string urlAndMethod, IDictionary<string, object> dicParam)
        {
            string param = JsonXmlUtils.SerializeObject(dicParam);
            // string param = ToolHelper.BuildQuery(dicParam);
            string result = string.Empty;
            //string param = string.Empty;
            byte[] bytes = null;

            Stream writer = null;
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            bytes = Encoding.UTF8.GetBytes(param);

            request = (HttpWebRequest)WebRequest.Create(urlAndMethod);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = bytes.Length;

            try
            {
                writer = request.GetRequestStream();        //获取用于写入请求数据的Stream对象
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }

            writer.Write(bytes, 0, bytes.Length);       //把参数数据写入请求数据流
            writer.Close();

            try
            {
                response = (HttpWebResponse)request.GetResponse();      //获得响应
            }
            catch (WebException ex)
            {
                return ex.ToString();
            }


            return GetResponseAsString(response, Encoding.UTF8);
        }

        public string DoPost(string url, string xml, string contenttype = "application/x-www-form-urlencoded", string charset = "utf-8")
        {
            return RemotePost(url, xml, contenttype, charset);
        }

        /// <summary>
        /// 执行HTTP POST请求。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <param name="charset">编码字符集</param>
        /// <returns>HTTP响应</returns>
        public string DoPost(string url, IDictionary<string, object> parameters, string contenttype = "application/x-www-form-urlencoded", string charset = "utf-8")
        {
            return RemotePost(url, parameters, contenttype, charset);
        }

        public string RemotePost(string url, string content, string contentType = "application/json",
            string charset = "utf-8"
            , X509Certificate2 cert2 = null)
        {
            HttpWebRequest req = GetWebRequest(url, "POST");
            req.ContentType = contentType + ";charset=" + charset;
            req.Accept = contentType + ";charset=" + charset;

            byte[] postData = Encoding.GetEncoding(charset).GetBytes(content);

            Stream reqStream = req.GetRequestStream();
            reqStream.Write(postData, 0, postData.Length);
            reqStream.Close();
            if (cert2 != null)
                req.ClientCertificates.Add(cert2);
            HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
            Encoding encoding = Encoding.GetEncoding(charset);
            return GetResponseAsString(rsp, encoding);
        }

        public string DoPost(string url, List<KeyValuePair<string, object>> paramters, string charset, string contenttype = "application/x-www-form-urlencoded")
        {
            HttpWebRequest req = GetWebRequest(url, "POST");

            req.ContentType = contenttype + ";charset=" + charset;
            req.Accept = contenttype + ";charset=" + charset;
            string dataStr = ToolHelper.BuildQuery(paramters.GetEnumerator(), charset);

            byte[] postData = Encoding.GetEncoding(charset).GetBytes(dataStr);
            Stream reqStream = req.GetRequestStream();
            reqStream.Write(postData, 0, postData.Length);
            reqStream.Close();

            HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
            Encoding encoding = Encoding.GetEncoding(string.IsNullOrWhiteSpace(rsp.CharacterSet) ? charset : rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }

        public string DoPostBasicAuth(string uri, string json)
        {
            Uri address = new Uri(uri);
            HttpWebRequest request;
            //HttpWebResponse response1 = null;
            StreamReader sr;
            string returnXML = string.Empty;
            if (address == null) { throw new ArgumentNullException("address"); }
            try
            {
                request = WebRequest.Create(address) as HttpWebRequest;
                request.Method = "POST";
                request.ContentType = "application/json";
                string base64Credentials = GetEncodedCredentials();
                request.Headers.Add("Authorization", "Basic " + base64Credentials);
                //request.Credentials = new NetworkCredential(sUsername, sPassword);
                if (!string.IsNullOrEmpty(json))
                {
                    byte[] byteData = Encoding.UTF8.GetBytes(json);
                    request.ContentLength = byteData.Length;
                    using (Stream postStream = request.GetRequestStream())
                    {
                        postStream.Write(byteData, 0, byteData.Length);
                    }
                    using (HttpWebResponse response1 = request.GetResponse() as HttpWebResponse)
                    {
                        StreamReader reader = new StreamReader(response1.GetResponseStream());
                        string str = reader.ReadToEnd();
                        return str;

                    }
                }
                return "error";

            }
            catch (WebException wex)
            {

                if (wex.Response != null)
                {

                    using (HttpWebResponse errorResponse = (HttpWebResponse)wex.Response)
                    {
                        try
                        {
                            string sError = string.Format("The server returned '{0}' with the status code {1} ({2:d}).",
                            errorResponse.StatusDescription, errorResponse.StatusCode,
                            errorResponse.StatusCode);
                            sr = new StreamReader(errorResponse.GetResponseStream(), Encoding.UTF8);
                            returnXML = sr.ReadToEnd();
                            return returnXML;

                        }
                        finally
                        {
                            if (errorResponse != null) errorResponse.Close();
                        }
                    }
                }
                else
                {
                    //throw new Exception(wex.Message);
                    return wex.Message;

                }
            }
        }

        private string GetEncodedCredentials()
        {
            string mergedCredentials = string.Format("{0}:{1}", m_Username, m_Password);
            byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
            return Convert.ToBase64String(byteCredentials);
        }

        private string RemotePost(string url, object parameters, string contenttype = "application/x-www-form-urlencoded", string charset = "utf-8")
        {
            HttpWebRequest req = GetWebRequest(url, "POST");

            req.ContentType = contenttype + ";charset=" + charset;
            req.Accept = contenttype + ";charset=" + charset;
            string dataStr = string.Empty;
            if (parameters is string)
            {
                dataStr = parameters.ToString();
            }
            else if (parameters is IDictionary<string, object>)
            {
                IDictionary<string, object> dic = parameters as IDictionary<string, object>;
                if (contenttype.Contains("application/json"))
                {
                    dataStr = JsonXmlUtils.SerializeObject(dic);
                }
                else
                {
                    dataStr = ToolHelper.BuildQuery(parameters as IDictionary<string, object>, charset);
                }
            }
            byte[] postData = Encoding.GetEncoding(charset).GetBytes(dataStr);
            Stream reqStream = req.GetRequestStream();
            reqStream.Write(postData, 0, postData.Length);
            reqStream.Close();

            HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
            Encoding encoding = Encoding.GetEncoding(string.IsNullOrWhiteSpace(rsp.CharacterSet) ? charset : rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }

        /// <summary>
        /// 执行HTTP GET请求。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数</param>
        /// <param name="charset">编码字符集</param>
        /// <returns>HTTP响应</returns>
        public string DoGet(string url, IDictionary<string, object> parameters, string charset)
        {
            if (parameters != null && parameters.Count > 0)
            {
                if (url.Contains("?"))
                {
                    url = url + "&" + ToolHelper.BuildQuery(parameters, charset);
                }
                else
                {
                    url = url + "?" + ToolHelper.BuildQuery(parameters, charset);
                }
            }

            HttpWebRequest req = GetWebRequest(url, "GET");
            req.ContentType = "application/x-www-form-urlencoded;charset=" + charset;

            HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
            Encoding encoding = Encoding.GetEncoding(string.IsNullOrWhiteSpace(rsp.CharacterSet) ? charset : rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }

        public string DoGet(string url, string charset, List<KeyValuePair<string, object>> headers = null)
        {
            HttpWebRequest req = GetWebRequest(url, "GET");
            req.ContentType = "application/x-www-form-urlencoded;charset=" + charset;

            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    string val = string.Empty;
                    if (item.Value != null)
                        val = item.Value.ToString();
                    req.Headers.Add(item.Key, val);
                }
            }

            HttpWebResponse rsp;
            try
            {
                rsp = (HttpWebResponse)req.GetResponse();
            }
            catch (WebException wx)
            {
                rsp = (HttpWebResponse)wx.Response;
            }
            Encoding encoding = Encoding.GetEncoding(string.IsNullOrWhiteSpace(rsp.CharacterSet) ? charset : rsp.CharacterSet);
            return GetResponseAsString(rsp, encoding);
        }


        public static string BuildSignContent(string reqMethod, string apiUri, string timeStamp, string randomStr, string body)
        {
            string message = $"{reqMethod}\n{apiUri}\n{timeStamp}\n{randomStr}\n{body}\n";
            return message;
        }

        public static string GetHeader(string mchid, string randomStr, string sign, string timeStamp, string SerialNumber)
        {
            return $"WECHATPAY2-SHA256-RSA2048 mchid=\"{mchid}\",nonce_str=\"{randomStr}\",timestamp=\"{timeStamp}\",serial_no=\"{SerialNumber}\",signature=\"{sign}\"";
        }

        private HttpWebRequest GetWebRequest(string url, string method)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.ServicePoint.Expect100Continue = false;
            req.Method = method;
            req.KeepAlive = true;
            req.UserAgent = "Aop4Net";
            req.Timeout = this._timeout;
            return req;
        }

        /// <summary>
        /// 把响应流转换为文本。
        /// </summary>
        /// <param name="rsp">响应流对象</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>响应文本</returns>
        private static string GetResponseAsString(HttpWebResponse rsp, Encoding encoding)
        {
            StringBuilder result = new StringBuilder();
            Stream stream = null;
            StreamReader reader = null;

            try
            {
                // 以字符流的方式读取HTTP响应
                stream = rsp.GetResponseStream();
                reader = new StreamReader(stream, encoding);

                // 按字符读取并写入字符串缓冲
                int ch = -1;
                while ((ch = reader.Read()) > -1)
                {
                    // 过滤结束符
                    char c = (char)ch;
                    if (c != '\0')
                    {
                        result.Append(c);
                    }
                }
            }
            finally
            {
                // 释放资源
                if (reader != null) reader.Close();
                if (stream != null) stream.Close();
                if (rsp != null) rsp.Close();
            }

            return result.ToString();
        }

    }
}
